/*
 * iconvWrapper.cpp
 *
 *  Created on: 2014. 4. 25.
 *      Author: khs
 */


#include "IconvWrapper.h"

using namespace std;

IconvWrapper::IconvWrapper(){
 conversion_descriptor = 0;
 tocode_cache = NULL;
 fromcode_cache = NULL;
}

IconvWrapper::~IconvWrapper(){
 close();
}

iconv_t IconvWrapper::open(const char* tocode, const char* fromcode){
 if(conversion_descriptor > 0){
 close();
 }
 iconv_t ret = iconv_open(tocode, fromcode);
 if(ret > 0) {
 conversion_descriptor = ret;
 tocode_cache = new char[strlen(tocode) + 1];
 strcpy(tocode_cache, tocode);
 fromcode_cache = new char[strlen(fromcode) + 1];
 strcpy(fromcode_cache, fromcode);
 }
 else{
 conversion_descriptor = 0;
 }
 return conversion_descriptor ;
}

void IconvWrapper::close(){
 if(conversion_descriptor > 0){
 iconv_close(conversion_descriptor );
 conversion_descriptor = 0;
 }

 if(tocode_cache){
 delete [] tocode_cache;
 tocode_cache = NULL;
 }

 if(fromcode_cache){
 delete [] fromcode_cache;
 fromcode_cache = NULL;
 }
}

string IconvWrapper::from_to(string src, string fromcode, string tocode){
 string ret;
 int break_flag=0;

 if (!tocode_cache || !fromcode_cache || tocode != tocode_cache || fromcode != fromcode_cache) {
 open(tocode.c_str(), fromcode.c_str());
 }
 char* inbuf = const_cast<char*>(src.c_str());
 size_t inbytesleft = src.size();

 char* dst = new char[inbytesleft*2+1];
 char* outbuf = dst;
 size_t outbytesleft = inbytesleft;
 size_t dstmax = inbytesleft;

 while (inbytesleft > 0) {
 char* inbuf_org = inbuf;
 size_t n = iconv(conversion_descriptor , &inbuf, &inbytesleft, &outbuf, &outbytesleft);
 if ((n != (size_t)-1 && inbytesleft == 0) || (errno == EINVAL)) {
 /* EINVAL = An incomplete multibyte sequence has been encountered in the input. */
 inbytesleft = 0;
 ret.append(dst, 0, dstmax-outbytesleft);
 }
 else {

 switch (errno) {
 case E2BIG: /* There is not sufficient room at *outbuf. And something wrong can happen, so break the loop*/
 ret.append(dst, 0, dstmax-outbytesleft);
 outbuf = dst;
 outbytesleft = dstmax;
 break_flag++;
 break;
 case EILSEQ: /* An invalid multibyte sequence has been encountered in the input. */
 ret.append(dst, 0, dstmax-outbytesleft);
 ret.append(inbuf, 0, 1);
 inbuf++;
 inbytesleft--;
 outbuf = dst;
 outbytesleft = dstmax;
 break;
 default:
 ret.append(inbuf_org);
 inbytesleft = 0;
 break;
 }

 if(break_flag){
 break;
 }
 }
 }
 outbuf = dst;
 outbytesleft = dstmax;
 if ( iconv(conversion_descriptor , NULL, NULL, &outbuf, &outbytesleft) != (size_t)-1) {
 ret.append(dst, 0, dstmax-outbytesleft);
 }
 delete [] dst;
 return ret;
}

